#pragma once
#include "dll_export.h"
#include "RemoteEngine.h"
#include <boost/serialization/serialization.hpp>
#include <boost/weak_ptr.hpp>
#include <string>
#include <set>

LUA_DEBUG_BEGIN

/**
* @brief Break point object for the debugger.
*/
class _LUAVM_API Breakpoint
{
    std::string m_key;
    int m_line;
    bool m_isInternal;
    bool m_isTemp;

private:
    friend class boost::serialization::access;
    template<class Archive> void serialize(Archive& ar, const unsigned int) {
        ar & LLDEBUG_MEMBER_NVP(key);
        ar & LLDEBUG_MEMBER_NVP(line);
    }

public:
    explicit Breakpoint(const std::string &key = std::string(""), int line = 0,
        bool isInternal = false, bool isTemp = false);
    ~Breakpoint();

    /// Is this valid ?
    bool IsOk() const {
        return !m_key.empty();
    }

    /// Get the key of source file.
    const std::string &GetKey() const {
        return m_key;
    }

    /// Get the line number.
    int GetLine() const {
        return m_line;
    }

    /// Is this a internal breakpoint ? (user can't see it)
    bool IsInternal() const {
        return m_isInternal;
    }

    /// Is this a temporary breakpoint ?
    bool IsTemp() const {
        return m_isTemp;
    }

    friend bool operator < (const Breakpoint &x, const Breakpoint &y) {
        return (x.GetKey() < y.GetKey()) || (x.GetKey() == y.GetKey() && x.GetLine() < y.GetLine());
    }
};

/**
* @brief Break point list.
*/
class _LUAVM_API BreakpointList
{
    boost::weak_ptr<RemoteEngine> m_engine;

    typedef std::set<Breakpoint> ImplSet;
    ImplSet m_set;

private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& ar, const unsigned int) {
        ar & LLDEBUG_MEMBER_NVP(set);
    }

public:
    explicit BreakpointList(RemoteEngine_ptr engine);
    virtual ~BreakpointList();

    /// Find the breakpoint from key and line.
    Breakpoint Find(const std::string &key, int line);

    /// Find the first breakpoint of the key.
    Breakpoint First(const std::string &key);

    /// Find the next breakpoint (same key and bigger line).
    Breakpoint Next(const Breakpoint &bp);

    /// Set the new breakpoint.
    void Set(const Breakpoint &bp);

    /// Remove the breakpoint.
    void Remove(const Breakpoint &bp);

    /// Toggle on/off of the breakpoint.
    void Toggle(const std::string &key, int line);
};

LUA_DEBUG_END
